﻿using System.Collections;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using Noria.Web.MyMSDN.Models;

namespace Noria.Web.MyMSDN.Workers
{
    internal class MsdnCategoryWorker
    {
        private static readonly log4net.ILog slog = log4net.LogManager.GetLogger("Noria.Spider");
        private static readonly log4net.ILog alog = log4net.LogManager.GetLogger("Noria.Audit");

        private readonly string url;

        public MsdnCategoryWorker(string url)
        {
            this.url = url;
        }

        public IEnumerable<Category> RetrieveCategoryList(IStatistics stat, AsyncWaiter waiter)
        {
            dynamic catArray = HttpBot.RequestJArray(stat, url);

            // check alive
            if (!waiter.IsAlive)
                return new Category[] { };

            // convert
            var cats = new List<Category>();
            foreach (dynamic category in (IEnumerable)catArray)
            {
                var cat = new Category
                    {
                        CategoryId = (long)category.ProductGroupId,
                        Name = (string)category.Name,
                    };

                // skip category of 'new product'
                if (cat.CategoryId != 65)
                {
                    cats.Add(cat);
                }
            }

            // log
            slog.InfoFormat("MSDN Category retrieved, len={0}", cats.Count);
            foreach (var cat in cats)
            {
                slog.InfoFormat("Category -> Name: {0}, Id: {1}.",
                                cat.Name, cat.CategoryId);
            }

            return cats;
        }

        public void Save(IStatistics stat, IEnumerable<Category> cats)
        {
            // diff with db, update if necessary
            using (var db = new MmContext())
            {
                var dbCats = db.Categories.ToArray();

                MergeCategory(stat, cats, dbCats, db.Categories);

                int ret = db.SaveChanges();
                alog.InfoFormat("Category updated, count={0}", ret);
            }
        }

        private void MergeCategory(IStatistics stat, IEnumerable<Category> memory, IEnumerable<Category> db, DbSet<Category> context)
        {
            foreach (var cat in memory)
            {
                var dbCat = db.FirstOrDefault(p => p.CategoryId == cat.CategoryId);
                if (dbCat != null)
                {
                    bool updated = false;

                    if (!dbCat.Enabled)
                    {
                        // update
                        dbCat.Enabled = true;
                        updated = true;
                    }

                    if (dbCat.Name != cat.Name)
                    {
                        // update
                        dbCat.Name = cat.Name;
                        updated = true;
                    }

                    if (updated)
                    {
                        stat.AddUpdated();
                    }
                }
                else
                {
                    // insert
                    cat.Enabled = true;
                    context.Add(cat);
                    stat.AddInserted();
                }
            }

            foreach (var dbCat in db)
            {
                if (memory.All(p => p.CategoryId != dbCat.CategoryId))
                {
                    // delete
                    if (dbCat.Enabled)
                    {
                        dbCat.Enabled = false;
                        stat.AddDeleted();
                    }
                }
            }
        }

    }
}